import os
import time
from PyPDF2 import PdfMerger, PdfReader
from docx2pdf import convert
from PIL import Image
import win32com.client
import comtypes.client
from pdf2image import convert_from_path
import fitz  # PyMuPDF
import sys
from pathlib import Path
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import letter
import subprocess
import pythoncom

class FileConverter:
    @staticmethod
    def _setup_poppler():
        """设置 poppler 环境"""
        try:
            # 获取项目根目录
            root_dir = Path(__file__).parent.parent.parent
            
            # poppler 路径（假设在项目的 tools/poppler 目录下）
            poppler_path = root_dir / "tools" / "poppler" / "bin"
            
            if sys.platform.startswith('win'):
                # 将 poppler 路径添加到环境变量
                if poppler_path.exists():
                    os.environ["PATH"] = f"{poppler_path};{os.environ['PATH']}"
                else:
                    raise FileNotFoundError(
                        "未找到 poppler，请按照以下步骤安装：\n"
                        "1. 下载 poppler：https://github.com/oschwartz10612/poppler-windows/releases\n"
                        "2. 解压到项目的 tools/poppler 目录下\n"
                        "   或者将 poppler 添加到系统环境变量"
                    )
        except Exception as e:
            raise RuntimeError(f"设置 poppler 环境失败: {str(e)}")

    @staticmethod
    def convert_to_pdf(input_file, output_file, progress_callback=None):
        """将各种格式的文件转换为PDF"""
        file_extension = os.path.splitext(input_file)[1].lower()
        
        try:
            if progress_callback:
                progress_callback(10)  # 开始转换
                
            if file_extension == '.pdf':
                FileConverter.copy_pdf_file_to_temp(input_file, output_file)
            elif file_extension in ['.doc', '.docx']:
                FileConverter.word_to_pdf(input_file, output_file)
            elif file_extension in ['.xls', '.xlsx']:
                FileConverter.excel_to_pdf(input_file, output_file)
            elif file_extension in ['.jpg', '.jpeg', '.png', '.gif']:
                FileConverter.image_to_pdf(input_file, output_file)
            elif file_extension in ['.ppt', '.pptx']:
                FileConverter.ppt_to_pdf(input_file, output_file)
            else:
                raise ValueError(f"不支持的文件格式: {file_extension}")
                
            if progress_callback:
                progress_callback(100)  # 转换完成
                
            return output_file
        except Exception as e:
            if progress_callback:
                progress_callback(-1)  # 转换失败
            raise e

    @staticmethod
    def image_to_pdf(input_file, output_file):
        img = Image.open(input_file)
        img_pdf = img.convert('RGB')
        img_pdf.save(output_file, 'PDF', resolution=100.0)

    @staticmethod
    def excel_to_pdf(input_file, output_file):
        xlApp = DispatchEx("Excel.Application")
        xlApp.Visible = False
        xlApp.DisplayAlerts = 0
        books = xlApp.Workbooks.Open(input_file, False)
        books.ExportAsFixedFormat(0, output_file)
        books.Close(False)
        xlApp.Quit()

    @staticmethod
    def word_to_pdf(input_file, output_file):
        convert(input_file, output_file)

    @staticmethod
    def ppt_to_pdf(input_file, output_file):
        """将PowerPoint文件转换为PDF"""
        powerpoint = None
        try:
            # 转换为绝对路径
            input_file = os.path.abspath(input_file)
            output_file = os.path.abspath(output_file)
            
            # 确保输出目录存在
            os.makedirs(os.path.dirname(output_file), exist_ok=True)
            
            # 初始化 COM
            pythoncom.CoInitialize()
            
            # 创建PDF
            powerpoint = comtypes.client.CreateObject("Powerpoint.Application")
            powerpoint.Visible = 1
            
            # 等待 PowerPoint 完全启动
            time.sleep(1)
            
            # 打开演示文稿
            slides = powerpoint.Presentations.Open(input_file)
            
            # 等待文件完全加载
            time.sleep(1)
            
            # 保存PDF (ppSaveAsPDF = 32)
            slides.SaveAs(output_file, 32)
            
            # 关闭演示文稿
            slides.Close()
            
        except Exception as e:
            raise Exception(f"PowerPoint转换失败: {str(e)}")
        
        finally:
            # 确保关闭PowerPoint应用
            if powerpoint:
                try:
                    powerpoint.Quit()
                except:
                    pass
            # 清理 COM
            try:
                pythoncom.CoUninitialize()
            except:
                pass

    @staticmethod
    def copy_pdf_file_to_temp(src_file, output_file):
        with open(src_file, 'rb') as f_src:
            with open(output_file, 'wb') as f_dest:
                f_dest.write(f_src.read())
        return output_file 

    @staticmethod
    def get_pdf_info(pdf_file):
        """获取PDF文件信息"""
        doc = fitz.open(pdf_file)
        info = {
            'pages': len(doc),
            'title': doc.metadata.get('title', ''),
            'author': doc.metadata.get('author', ''),
            'subject': doc.metadata.get('subject', ''),
            'keywords': doc.metadata.get('keywords', '')
        }
        doc.close()
        return info
    
    @staticmethod
    def pdf_to_image(input_file, output_file, page_number=0, zoom=1):
        """将PDF转换为图片
        Args:
            input_file: PDF文件路径
            output_file: 输出图片路径
            page_number: PDF页码（从0开始）
            zoom: 缩放比例，值越大图片越清晰（默认值4，相当于400%）
        """
        try:
            # 打开PDF文件
            doc = fitz.open(input_file)
            
            # 获取指定页面
            page = doc[page_number]
            
            # 设置转换参数
            matrix = fitz.Matrix(zoom, zoom)  # 设置分辨率
            pix = page.get_pixmap(matrix=matrix, alpha=False)
            
            # 保存图片
            pix.save(output_file)
            
            # 关闭文档
            doc.close()
            
        except Exception as e:
            raise RuntimeError(f"PDF转换失败：{str(e)}") 

    @staticmethod
    def merge_images_to_pdf(image_files, output_file, progress_callback=None):
        """将多张图片合并为一个PDF文件
        Args:
            image_files: 图片文件路径列表
            output_file: 输出的PDF文件路径
            progress_callback: 进度回调函数
        """
        try:
            # 创建一个空的PDF文件
            c = canvas.Canvas(output_file, pagesize=letter)
            total = len(image_files)
            
            for i, img_path in enumerate(image_files):
                # 打开图片
                img = Image.open(img_path)
                
                # 转换为RGB模式（如果是RGBA）
                if img.mode == 'RGBA':
                    img = img.convert('RGB')
                
                # 计算图片在PDF中的大小和位置
                img_width, img_height = img.size
                aspect = img_height / float(img_width)
                
                # 设置PDF页面大小
                if aspect > 1:
                    pdf_width = letter[0] - 40
                    pdf_height = pdf_width * aspect
                else:
                    pdf_height = letter[1] - 40
                    pdf_width = pdf_height / aspect
                
                # 保存为临时文件
                temp_file = f"temp_{i}.jpg"
                img.save(temp_file, "JPEG")
                
                # 添加到PDF
                c.drawImage(temp_file, 20, letter[1] - pdf_height - 20,
                           width=pdf_width, height=pdf_height)
                
                # 删除临时文件
                os.remove(temp_file)
                
                # 如果不是最后一页，添加新页面
                if i < total - 1:
                    c.showPage()
                
                # 更新进度
                if progress_callback:
                    progress = ((i + 1) / total) * 100
                    progress_callback(int(progress))
            
            # 保存PDF
            c.save()
            
        except Exception as e:
            raise RuntimeError(f"图片合并失败：{str(e)}") 

    @staticmethod
    def convert_doc_to_pdf(input_file, output_file):
        """将Word文档转换为PDF"""
        pythoncom.CoInitialize()  # 初始化COM
        try:
            word = win32com.client.Dispatch("Word.Application")
            word.Visible = False
            doc = word.Documents.Open(input_file)
            doc.SaveAs(output_file, FileFormat=17)  # 17 represents PDF format
            doc.Close()
            word.Quit()
        finally:
            pythoncom.CoUninitialize()

    @staticmethod
    def convert_excel_to_pdf(input_file, output_file):
        """将Excel文件转换为PDF"""
        pythoncom.CoInitialize()
        try:
            excel = win32com.client.Dispatch("Excel.Application")
            excel.Visible = False
            wb = excel.Workbooks.Open(input_file)
            wb.ExportAsFixedFormat(0, output_file)  # 0 represents PDF format
            wb.Close()
            excel.Quit()
        finally:
            pythoncom.CoUninitialize()

    @staticmethod
    def convert_ppt_to_pdf(input_file, output_file):
        """将PowerPoint文件转换为PDF"""
        powerpoint = None
        try:
            # 转换为绝对路径
            input_file = os.path.abspath(input_file)
            output_file = os.path.abspath(output_file)
            
            # 确保输出目录存在
            os.makedirs(os.path.dirname(output_file), exist_ok=True)
            
            # 初始化 COM
            pythoncom.CoInitialize()
            
            # 创建PDF
            powerpoint = comtypes.client.CreateObject("Powerpoint.Application")
            powerpoint.Visible = 1
            
            # 等待 PowerPoint 完全启动
            time.sleep(1)
            
            # 打开演示文稿
            slides = powerpoint.Presentations.Open(input_file)
            
            # 等待文件完全加载
            time.sleep(1)
            
            # 保存PDF (ppSaveAsPDF = 32)
            slides.SaveAs(output_file, 32)
            
            # 关闭演示文稿
            slides.Close()
            
        except Exception as e:
            raise Exception(f"PowerPoint转换失败: {str(e)}")
        
        finally:
            # 确保关闭PowerPoint应用
            if powerpoint:
                try:
                    powerpoint.Quit()
                except:
                    pass
            # 清理 COM
            try:
                pythoncom.CoUninitialize()
            except:
                pass

    @staticmethod
    def convert_image_to_pdf(input_file, output_file):
        """将图片转换为PDF"""
        try:
            image = Image.open(input_file)
            # 如果图片是PNG格式且有透明通道，转换为RGB
            if image.mode in ('RGBA', 'LA') or \
                (image.mode == 'P' and 'transparency' in image.info):
                background = Image.new('RGB', image.size, (255, 255, 255))
                if image.mode == 'P':
                    image = image.convert('RGBA')
                background.paste(image, mask=image.split()[-1])
                image = background
            elif image.mode != 'RGB':
                image = image.convert('RGB')
            image.save(output_file, 'PDF', resolution=100.0)
        except Exception as e:
            raise Exception(f"图片转换失败: {str(e)}")

    @staticmethod
    def convert_text_to_pdf(input_file, output_file):
        """将文本文件转换为PDF
        支持的格式：txt, md, sql, html, rtf, log 等文本文件
        """
        try:
            # 导入所需的字体支持
            from reportlab.pdfbase import pdfmetrics
            from reportlab.pdfbase.ttfonts import TTFont
            
            # 注册中文字体（使用系统自带的微软雅黑字体）
            try:
                # Windows 系统字体路径
                font_path = "C:/Windows/Fonts/msyh.ttc"
                pdfmetrics.registerFont(TTFont('MicrosoftYaHei', font_path))
                default_font = 'MicrosoftYaHei'
            except:
                try:
                    # Linux/Mac 系统可能的字体路径
                    font_path = "/System/Library/Fonts/PingFang.ttc"
                    pdfmetrics.registerFont(TTFont('PingFang', font_path))
                    default_font = 'PingFang'
                except:
                    # 如果都失败，使用默认字体
                    default_font = 'Helvetica'
            
            # 使用 reportlab 创建 PDF
            c = canvas.Canvas(output_file, pagesize=letter)
            
            # 设置字体和大小
            c.setFont(default_font, 10)
            
            # 设置页面边距和起始位置
            margin = 50
            y = letter[1] - margin  # 起始位置
            line_height = 14  # 行高
            max_width = letter[0] - 2 * margin  # 最大行宽
            
            try:
                # 首先尝试 UTF-8 编码
                with open(input_file, 'r', encoding='utf-8') as f:
                    content = f.readlines()
            except UnicodeDecodeError:
                # 如果失败，尝试系统默认编码
                with open(input_file, 'r', encoding='gbk') as f:
                    content = f.readlines()
            
            # 处理每一行文本
            for line in content:
                # 移除行尾的空白字符
                line = line.rstrip()
                
                if not line:  # 空行处理
                    y -= line_height
                    if y <= margin:
                        c.showPage()
                        c.setFont(default_font, 10)  # 新页面需要重新设置字体
                        y = letter[1] - margin
                    continue
                
                # 处理长行，进行自动换行
                while line:
                    # 计算当前行能容纳的文字数量
                    for i in range(len(line), 0, -1):
                        if c.stringWidth(line[:i], default_font, 10) <= max_width:
                            if i < len(line):
                                # 在单词边界处换行
                                last_space = line[:i].rfind(' ')
                                if last_space > 0:
                                    i = last_space
                            break
                    
                    # 绘制当前行
                    c.drawString(margin, y, line[:i])
                    line = line[i:].strip()
                    
                    # 处理下一行
                    y -= line_height
                    if y <= margin:
                        c.showPage()
                        c.setFont(default_font, 10)  # 新页面需要重新设置字体
                        y = letter[1] - margin
            
            # 保存PDF
            c.save()
            
        except Exception as e:
            raise Exception(f"文本转换失败: {str(e)}")

    @staticmethod
    def merge_pdfs(input_files, output_file):
        """合并多个PDF文件"""
        try:
            merger = PdfMerger()
            
            # 添加所有PDF文件
            for pdf in input_files:
                if os.path.exists(pdf):  # 确保文件存在
                    merger.append(pdf)
                else:
                    raise Exception(f"找不到文件: {pdf}")
            
            # 保存合并后的文件
            merger.write(output_file)
            merger.close()
            
        except Exception as e:
            raise Exception(f"PDF合并失败: {str(e)}")